package com.my.netty.optimize.backlog;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.AdaptiveRecvByteBufAllocator;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class BacklogServer {

    public static void main(String[] args) {
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            /*
                配置backlog参数，即ServerSocketChannel参数，即TCP全连接队列大小。（linux系统会取此处配置和系统配置的最小值）
                每次TCP3次握手完成后，服务端将建立好的连接放入全连接队列
                每次调用accept，服务器从全连接队列取出一个连接处理
                全连接队列满了之后，无法再建立连接，如果客户端再连接会抛出拒绝连接异常
                //SO_BACKLOG默认值源码位置 io.netty.util.NetUtil.SoMaxConnAction.run
             */
            //测试时需要加断点
            //io.netty.channel.nio.NioEventLoop.processSelectedKey(java.nio.channels.SelectionKey, io.netty.channel.nio.AbstractNioChannel) 位置：788 unsafe.read();
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 2);

            /*
                TCP_NODELAY
                因为Nagle算法，数据包会堆积到一定的数量后一起发送，这就可能导致数据的发送存在一定的延时，该参数默认为false
                如果不希望的发送被延时，则需要将该值设置为true
                属于SocketChannel参数
            */
            serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);

            /*
                SO_SNDBUF & SO_RCVBUF
                SO_SNDBUF属于SocketChannel参数
                SO_RCVBUF既可用于SocketChannel参数，也可以用于ServerSocketChannel参数（建议设置到ServerSocketChannel上）
                该参数用于指定接收方与发送方的滑动窗口大小。目前操作系统都支持在通信时实时调整滑动窗口大小，一般不需要在应用程序中调整这两个参数。
             */
            serverBootstrap.childOption(ChannelOption.SO_SNDBUF, 1024);
            serverBootstrap.option(ChannelOption.SO_RCVBUF, 1024);

            /*
                RCVBUF_ALLOCATOR
                属于SocketChannal参数，控制Netty接收缓冲区大小
                负责入站数据的分配channelRead的msg，决定入站缓冲区的大小（并可动态调整），统一采用direct直接内存，具体池化还是非池化由allocator决定
                默认值就是 AdaptiveRecvByteBufAllocator
             */
            serverBootstrap.option(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator());

            serverBootstrap.group(new NioEventLoopGroup());
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
                @Override
                protected void initChannel(NioSocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
                }
            });
            serverBootstrap.bind(8080).sync();
            log.info("服务端已启动...");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
